#ifndef _SE_CAMERA_
#define _SE_CAMERA_

#include "Core/Math.hpp"

namespace SE
{
	static constexpr Vector3f CameraWorldUp			= Vector3f(0.0f, 1.0f, 0.0f);
	static constexpr Vector3f CameraWorldRight		= Vector3f(1.0f, 0.0f, 0.0f);
	static constexpr Vector3f CameraWorldForward	= Vector3f(0.0f, 0.0f,-1.0f);

	class Camera final
	{
		enum class MoveDirection : U8
		{
			Forward, Backward, Left, Right, Up, Down
		};

	private:
		Vector3f	mPosition;
		Quaternion	mOrientation;  // Temporary.
		
		// For orthographic camera.
		Float		mOrthographicSize;
		Float		mOrthographicNear;
		Float		mOrthographicFar;
		Matrix4f	mOrthographicView;
		Matrix4f	mOrthographicProjection;
		Matrix4f	mOrthographicViewProjection;

		// For perspective camera.
		Float		mPerspectiveFOV;
		Float		mPerspectiveNear;
		Float		mPerspectiveFar;
		Matrix4f	mPerspectiveView;
		Matrix4f	mPerspectiveProjection;
		Matrix4f	mPerspectiveViewProjection;

	public:
		Camera();
		~Camera();

		// Camera transform.
		void rotate(const Vector3f& axis, const Float angle);
		void rotatePitch(const Float angle);
		void rotateYaw(const Float angle);
		void rotateRoll(const Float angle);
		void onMousePan(const Vector2f& delta);
		void onCameraMove(const Vector3f& delta);

		//---------------------------------------------------------
		/* Attributes getter */
		const Vector3f& getPosition() const;
		
		Float getOrthographicSize() const;
		Float getOrthographicNear() const;
		Float getOrthographicFar() const;

		const Matrix4f& getOrthographicView() const;
		const Matrix4f& getOrthographicProjection() const;
		const Matrix4f& getOrthographicViewProjection() const;

		Float getPerspectiveFOV() const;
		Float getPerspectiveNear() const;
		Float getPerspectiveFar() const;

		const Matrix4f& getPerspectiveView() const;
		const Matrix4f& getPerspectiveProjection() const;
		const Matrix4f& getPerspectiveViewProjection() const;

		Vector3f getUpDirection() const;
		Vector3f getRightDirection() const;
		Vector3f getForwardDirection() const;

		Vector3f getEulerAngles() const;
		Vector3f getEulerRadians() const;
		//---------------------------------------------------------

		//---------------------------------------------------------
		/* Attributes setter */
		void setPosition(const Vector3f& position);

		void setOrthographicSize(const Float size);
		void setOrthographicNear(const Float nearPlane);
		void setOrthographicFar(const Float farPlane);

		void setPerspectiveFOV(const Float fov);
		void setPerspectiveNear(const Float nearPlane);
		void setPerspectiveFar(const Float farPlane);

		void setEulerAngles(const Vector3f& eulerAngles);
		void setEulerRadians(const Vector3f& eulerRadians);
		//---------------------------------------------------------

	private:
		void recalculateOrthographicView();
		void recalculateOrthographicProjection();
		void recalculateOrthographicMatrices();

		void recalculatePerspectiveView();
		void recalculatePerspectiveProjection();
		void recalculatePerspectiveMatrices();
	};
} // !namespace SE

#endif // !_SE_CAMERA_